package avicit.bdp.dgs.metadata.service;

import avicit.bdp.approval.api.impl.MetadataApprovalApi;
import avicit.bdp.common.base.BaseService;
import avicit.bdp.common.dto.MetadataStateDto;
import avicit.bdp.common.dto.approval.ApprovalDTO;
import avicit.bdp.common.service.dto.*;
import avicit.bdp.common.service.service.CommonTypeService;
import avicit.bdp.common.service.service.DataQueryService;
import avicit.bdp.common.service.service.DataSourceService;
import avicit.bdp.common.utils.BdpLogUtil;
import avicit.bdp.common.utils.CheckParaUtils;
import avicit.bdp.common.utils.EntityUtils;
import avicit.bdp.common.utils.database.DBUtils;
import avicit.bdp.common.utils.enums.CommonTypeEnums;
import avicit.bdp.common.vo.CommonResVo;
import avicit.bdp.core.constant.Constants;
import avicit.bdp.core.datasource.enums.DataSourceType;
import avicit.bdp.core.enums.DataStateEnum;
import avicit.bdp.core.enums.TableTypeEnum;
import avicit.bdp.core.file.util.FileUtils;
import avicit.bdp.core.util.json.JSONUtils;
import avicit.bdp.dgs.metadata.dao.MetadataBusinessDao;
import avicit.bdp.dgs.metadata.dao.MetadataTableDao;
import avicit.bdp.dgs.metadata.dto.*;
import avicit.bdp.dgs.metadata.vo.MetadataBusinessVo;
import avicit.bdp.dgs.metadata.vo.MetadataTableColumnPartitionedVo;
import avicit.bdp.dgs.metadata.vo.MetadataTableColumnVo;
import avicit.bdp.dgs.metadata.vo.MetadataTableVo;
import avicit.bdp.dgs.standard.dto.LookupTableDto;
import avicit.bdp.dgs.standard.dto.LookupTableValueDto;
import avicit.bdp.dgs.standard.service.LookupTableService;
import avicit.bdp.dgs.standard.service.LookupTableValueService;
import avicit.platform6.api.system.ConvertColumnClient;
import avicit.platform6.api.system.SysUserClient;
import avicit.platform6.api.sysuser.dto.SysUser;
import avicit.platform6.commons.utils.BusinessUtil;
import avicit.platform6.commons.utils.ComUtil;
import avicit.platform6.core.context.ThreadContextHelper;
import avicit.platform6.core.exception.BusinessException;
import avicit.platform6.core.exception.DaoException;
import avicit.platform6.core.properties.PlatformConstant;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.google.common.collect.Lists;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 表类型元数据关系型数据库存储服务
 *
 * @author mayanj
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class MetadataTableService extends BaseService<MetadataTableDao, BdpTableDTO> {

  @Resource private MetadataTableColumnService metadataTableColumnService;
  @Resource private MetadataTableColumnPartitionService metadataTableColumnPartitionService;
  @Resource private MetadataTableHistoryService metadataTableHistoryService;
  @Resource private MetadataTableColumnHistoryService metadataTableColumnHistoryService;

  @Resource
  private MetadataTableColumnPartitionHistoryService metadataTableColumnPartitionHistoryService;

  @Resource private CommonTypeService commonTypeService;
  @Resource private MetadataApprovalApi metadataApprovalRpc;
  @Resource private MetadataBusinessDao metadataBusinessDao;
  @Resource private MetadataModelService metadataModelService;
  @Resource private MetadataModelAttributeService metadataModelAttributeService;
  @Resource private MetadataStateService metadataStateService;
  @Resource private LookupTableService lookupTableService;
  @Resource private LookupTableValueService lookupTableValueService;
  @Resource private DataQueryService dataQueryService;
  @Resource private DataSourceService dataSourceService;
  @Resource private MetadataTmpService metadataTmpService;
  @Autowired private ConvertColumnClient convertColumnClient;
  @Autowired private SysUserClient sysUserClient;

  @Transactional(readOnly = true)
  public Page<MetadataTableVo> getPageList(
      String datasourceType,
      String dataSourceId,
      String projectId,
      String catalogId,
      String keyWords,
      Integer status,
      Integer fromBaseVersion,
      Integer pageNo,
      Integer pageSize)
      throws Exception {

    List<String> typeIds = getTypeIds(projectId, catalogId);

    List<String> wordSecretList = ThreadContextHelper.getWordSecretList();
    PageHelper.startPage(pageNo, pageSize);

    Page<BdpTableDTO> pageList =
        this.mapper.queryTablePageList(
            datasourceType,
            dataSourceId,
            TableTypeEnum.TABLE_METADATA.getCode(),
            typeIds,
            keyWords,
            status,
            fromBaseVersion,
            wordSecretList);

    List<MetadataTableVo> voList = new ArrayList<>();
    List<BdpTableDTO> tableList = pageList.getResult();
    valueConvert(tableList);

    if (CollectionUtils.isNotEmpty(tableList)) {
      List<MetadataBusinessVo> businessVos = metadataBusinessDao.getMetadataBusinessAll(tableList);
      Map<String, MetadataBusinessVo> metadataBusinessMap =
          businessVos.stream()
              .collect(Collectors.toMap(MetadataBusinessVo::getMetadataId, Function.identity()));

      for (BdpTableDTO dasTableDTO : tableList) {
        MetadataTableVo tableVo = getMetadataTableVo(dasTableDTO);
        tableVo.setSecretLevel(dasTableDTO.getSecretLevel());
        tableVo.setSecretLevelName(dasTableDTO.getSecretLevelName());
        tableVo.setStatusStr(DataStateEnum.getDescByCode(dasTableDTO.getStatus()));

        if (metadataBusinessMap.containsKey(dasTableDTO.getId())) {
          MetadataBusinessVo metadataBusinessVo = metadataBusinessMap.get(dasTableDTO.getId());
          tableVo.setDomain(metadataBusinessVo.getDomainName());
          tableVo.setDataHierarchy(metadataBusinessVo.getLayerName());
          if (StringUtils.isNotBlank(metadataBusinessVo.getcName())) {
            tableVo.setCnName(metadataBusinessVo.getcName());
          } else {
            tableVo.setCnName(dasTableDTO.getCnName());
          }

          tableVo.setPublishAble(StringUtils.isEmpty(metadataBusinessVo.getTmpId()) ? 0 : 1);
        }

        voList.add(tableVo);
      }
    }

    Page<MetadataTableVo> page = new Page<>(pageNo, pageSize);
    page.setTotal(pageList.getTotal());
    page.addAll(voList);
    return page;
  }

  private void valueConvert(List<BdpTableDTO> tableList) {
    // 循环组装请求数据
    Map<String, Set<String>> convertFormData = new HashMap<>();
    if (CollectionUtils.isNotEmpty(tableList)) {
      for (BdpTableDTO tableDTO : tableList) {
        BusinessUtil.createConvertSet(convertFormData, Constants.BDP_DATA_SECRET_LEVEL_KEY, tableDTO.getSecretLevel());
      }
      if (convertFormData.size() > 0) {
        // 获取请求结果
        Map<String, Map<String, String>> convertResultData = convertColumnClient.replace(convertFormData);
        for (BdpTableDTO tableDTO : tableList) {
          tableDTO.setSecretLevelName(BusinessUtil.convertFormat(
                  convertResultData, Constants.BDP_DATA_SECRET_LEVEL_KEY, tableDTO.getSecretLevel()));
        }
      }
    }
  }

  @Transactional(readOnly = true)
  public Page<CommonResVo> getPageList2(
      String datasourceType,
      String dataSourceId,
      String projectId,
      String catalogId,
      String keyWords,
      Integer status,
      Integer type,
      Integer pageNo,
      Integer pageSize) {

    List<String> typeIds = getTypeIds(projectId, catalogId);
    List<String> wordSecretList = ThreadContextHelper.getWordSecretList();
    PageHelper.startPage(pageNo, pageSize);

    if (type == null) {
      type = TableTypeEnum.TABLE_METADATA.getCode();
    }

    // 元数据从基线版本查询
    int fromBaseVersion = 0;
    if (type == TableTypeEnum.TABLE_METADATA.getCode()) {
      fromBaseVersion = 1;
    }

    Page<BdpTableDTO> pageList =
        this.mapper.queryTablePageList(
            datasourceType, dataSourceId, type, typeIds, keyWords, status, fromBaseVersion, wordSecretList);

    List<CommonResVo> voList = new ArrayList<>();
    List<BdpTableDTO> tableList = pageList.getResult();

    for (BdpTableDTO dasTableDTO : tableList) {
      CommonResVo commonResVo =
          new CommonResVo(
              dasTableDTO.getId(), dasTableDTO.getName(), dasTableDTO.getTableVersion());
      voList.add(commonResVo);
    }

    Page<CommonResVo> page = new Page<>(pageNo, pageSize);
    page.setTotal(pageList.getTotal());
    page.addAll(voList);
    return page;
  }

  private List<String> getTypeIds(String projectId, String catalogId) {
    List<String> typeIds = Lists.newArrayList();
    if (StringUtils.isNotEmpty(catalogId)) {
      CommonTypeDTO rootCommonType =
          commonTypeService.selectRootByType(CommonTypeEnums.DATA_ASSET_CATALOG_TYPE);
      if (rootCommonType != null && !rootCommonType.getId().equalsIgnoreCase(catalogId)) {
        typeIds.addAll(
            commonTypeService.getChildrenIds(
                CommonTypeEnums.DATA_ASSET_CATALOG_TYPE, catalogId, projectId));
        typeIds.add(catalogId);
      }
    }
    return typeIds;
  }

  private MetadataTableVo getMetadataTableVo(BdpTableDTO dasTableDTO) {
    MetadataTableVo tableVo = new MetadataTableVo();

    tableVo.setId(dasTableDTO.getId());
    tableVo.setCatalogId(dasTableDTO.getTypeId());
    tableVo.setCatalogName(dasTableDTO.getTypeName());
    tableVo.setName(dasTableDTO.getName());
    tableVo.setCnName(dasTableDTO.getCnName());
    tableVo.setDataSourceId(dasTableDTO.getDataSourceId());
    tableVo.setDataSourceName(dasTableDTO.getDataSourceName());
    tableVo.setDataSourceType(dasTableDTO.getDataSourceType());
    tableVo.setStatus(dasTableDTO.getStatus());
    tableVo.setTableVersion(dasTableDTO.getTableVersion());
    tableVo.setBaseVersion(dasTableDTO.getBaseVersion());
    tableVo.setSecretLevel(dasTableDTO.getSecretLevel());

    List<BdpColumnDTO> columnList = dasTableDTO.getColumnList();
    if (CollectionUtils.isNotEmpty(columnList)) {
      List<MetadataTableColumnVo> columnVoList = new ArrayList<>();
      for (BdpColumnDTO bdpColumnDTO : columnList) {
        MetadataTableColumnVo columnVo = new MetadataTableColumnVo();
        BeanUtils.copyProperties(bdpColumnDTO, columnVo);
        columnVo.setOrderNo(bdpColumnDTO.getOrderBy());
        columnVo.setTableMetaId(bdpColumnDTO.getTableId());
        columnVoList.add(columnVo);
      }
      tableVo.setColumnList(columnVoList);
    }

    List<ColumnPartitionedDTO> columnPartitionedDTOS = dasTableDTO.getPartitionedColumnList();
    if (CollectionUtils.isNotEmpty(columnPartitionedDTOS)) {
      List<MetadataTableColumnPartitionedVo> columnPartitionedList = new ArrayList<>();
      for (ColumnPartitionedDTO columnPartitionedDTO : columnPartitionedDTOS) {
        MetadataTableColumnPartitionedVo columnPartitionedVo =
            new MetadataTableColumnPartitionedVo();
        BeanUtils.copyProperties(columnPartitionedDTO, columnPartitionedVo);
        columnPartitionedVo.setTableMetaId(columnPartitionedDTO.getTableId());
        columnPartitionedList.add(columnPartitionedVo);
      }
      tableVo.setColumnPartitionedList(columnPartitionedList);
    }

    return tableVo;
  }

  private void handleTableInfo(BdpTableDTO dasTableDTO) {
    if (dasTableDTO != null) {
      getColumnList(dasTableDTO);
      getPartitionColumnList(dasTableDTO);
    }
  }

  private void getPartitionColumnList(BdpTableDTO dasTableDTO) {
    ColumnPartitionedDTO columnPartitionedDTO = new ColumnPartitionedDTO();
    columnPartitionedDTO.setTableId(dasTableDTO.getId());
    List<ColumnPartitionedDTO> columnPartitionList =
        metadataTableColumnPartitionService.selectList(columnPartitionedDTO).stream()
            .sorted(Comparator.comparing(ColumnPartitionedDTO::getOrderBy))
            .collect(Collectors.toList());
    dasTableDTO.setPartitionedColumnList(columnPartitionList);
  }

  private void getColumnList(BdpTableDTO dasTableDTO) {
    BdpColumnDTO bdpDasColumnDTO = new BdpColumnDTO();
    bdpDasColumnDTO.setTableId(dasTableDTO.getId());
    List<BdpColumnDTO> columnList =
        metadataTableColumnService.selectList(bdpDasColumnDTO).stream()
            .sorted(Comparator.comparing(BdpColumnDTO::getOrderBy))
            .collect(Collectors.toList());
    dasTableDTO.setColumnList(columnList);
  }

  /**
   * 数据表元数据写入
   *
   * @param bdpDasTableDTO 新增数据表
   * @return 数据表ID
   */
  @Transactional(rollbackFor = Exception.class)
  public String insertDataTable(BdpTableDTO bdpDasTableDTO, String tableVersion) {

    if (StringUtils.isBlank(bdpDasTableDTO.getId())) {
      bdpDasTableDTO.setId(ComUtil.getId());
    }
    bdpDasTableDTO.setTableVersion(tableVersion);
    bdpDasTableDTO.setStatus(DataStateEnum.UNDER_EDITING.getCode());

    // 表的密级跟数据源密级保持一致
    DataSourceDTO dataSourceDTO = dataSourceService.queryDataSourceById(bdpDasTableDTO.getDataSourceId());
    if (dataSourceDTO != null) {
      bdpDasTableDTO.setSecretLevel(dataSourceDTO.getSecretLevel());
    }

    try {
      insertSelective(bdpDasTableDTO);
      BdpLogUtil.log4Insert(bdpDasTableDTO);

      BdpTableHistoryDTO tableHistoryDTO = new BdpTableHistoryDTO();
      BeanUtils.copyProperties(bdpDasTableDTO, tableHistoryDTO);
      tableHistoryDTO.setId(ComUtil.getId());
      tableHistoryDTO.setTableId(bdpDasTableDTO.getId());
      metadataTableHistoryService.insertSelective(tableHistoryDTO);

      // 新增字段信息
      List<BdpColumnDTO> columnDTOList = bdpDasTableDTO.getColumnList();
      if (CollectionUtils.isNotEmpty(columnDTOList)) {
        List<BdpColumnHistoryDTO> columnHistoryList = new ArrayList<>(columnDTOList.size());
        // 重新修改字段排序
        int orderBy = 1;
        for (BdpColumnDTO column : columnDTOList) {
          if (StringUtils.isBlank(column.getId())) {
            column.setId(ComUtil.getId());
          }
          column.setTableId(bdpDasTableDTO.getId());
          column.setCreatedBy(ThreadContextHelper.getUserId());
          column.setCreationDate(new Date());
          column.setOrderBy(orderBy);
          column.setModifyable(1);
          orderBy++;

          BdpColumnHistoryDTO columnHistory = new BdpColumnHistoryDTO();
          BeanUtils.copyProperties(column, columnHistory);
          columnHistory.setId(ComUtil.getId());
          columnHistory.setTableId(tableHistoryDTO.getId());
          EntityUtils.setCreateAndUpdateInfoWithoutVersion(columnHistory);
          columnHistoryList.add(columnHistory);
        }

        batchInsertColumn(columnDTOList);
        batchInsertHistoryColumn(columnHistoryList);
      }

      // 分区字段处理
      List<ColumnPartitionedDTO> partitionedColumnList = bdpDasTableDTO.getPartitionedColumnList();
      if (CollectionUtils.isNotEmpty(partitionedColumnList)) {
        List<ColumnPartitionedHistoryDTO> partitionedColumnHistoryList =
            new ArrayList<>(partitionedColumnList.size());
        int pOrderBy = 1;
        for (ColumnPartitionedDTO partitionedDTO : partitionedColumnList) {
          if (StringUtils.isBlank(partitionedDTO.getId())) {
            partitionedDTO.setId(ComUtil.getId());
          }
          partitionedDTO.setTableId(bdpDasTableDTO.getId());
          partitionedDTO.setCreatedBy(ThreadContextHelper.getUserId());
          partitionedDTO.setCreationDate(new Date());
          partitionedDTO.setOrderBy(pOrderBy);
          pOrderBy++;

          ColumnPartitionedHistoryDTO partitionedHistoryDTO = new ColumnPartitionedHistoryDTO();
          BeanUtils.copyProperties(partitionedDTO, partitionedHistoryDTO);
          partitionedHistoryDTO.setId(ComUtil.getId());
          partitionedHistoryDTO.setTableId(tableHistoryDTO.getId());
          EntityUtils.setCreateAndUpdateInfoWithoutVersion(partitionedHistoryDTO);
          partitionedColumnHistoryList.add(partitionedHistoryDTO);
        }

        batchInsertColumnPartition(partitionedColumnList);
        batchInsertColumnPartitionHistory(partitionedColumnHistoryList);
      }

      return bdpDasTableDTO.getId();
    } catch (Exception e) {
      throw new BusinessException(e.getMessage(), e);
    }
  }

  /**
   * 批量添加列
   *
   * @param allColumnList 待插入列数据
   */
  public void batchInsertColumn(List<BdpColumnDTO> allColumnList) {
    if (CollectionUtils.isNotEmpty(allColumnList)) {
      int start = 0;
      int totalSize = allColumnList.size();
      while (true) {
        // 以100条记录为单位分批存储
        int end = Math.min(start + 100, totalSize);
        metadataTableColumnService.batchInsert(allColumnList.subList(start, end));
        if (end >= totalSize) {
          break;
        }
        start = end;
      }
    }
  }

  /**
   * 批量添加列历史记录
   *
   * @param list 待插入列数据
   */
  public void batchInsertHistoryColumn(List<BdpColumnHistoryDTO> list) {
    if (CollectionUtils.isNotEmpty(list)) {
      int start = 0;
      int totalSize = list.size();
      while (true) {
        // 以100条记录为单位分批存储
        int end = Math.min(start + 100, totalSize);
        metadataTableColumnHistoryService.batchInsert(list.subList(start, end));
        if (end >= totalSize) {
          break;
        }
        start = end;
      }
    }
  }

  /**
   * 批量添加分区
   *
   * @param list 待插入列数据
   */
  public void batchInsertColumnPartition(List<ColumnPartitionedDTO> list) {
    if (CollectionUtils.isNotEmpty(list)) {
      int start = 0;
      int totalSize = list.size();
      while (true) {
        // 以100条记录为单位分批存储
        int end = Math.min(start + 100, totalSize);
        metadataTableColumnPartitionService.batchInsert(list.subList(start, end));
        if (end >= totalSize) {
          break;
        }
        start = end;
      }
    }
  }

  /**
   * 批量添加分区记录
   *
   * @param list 待插入列数据
   */
  public void batchInsertColumnPartitionHistory(List<ColumnPartitionedHistoryDTO> list) {
    if (CollectionUtils.isNotEmpty(list)) {
      int start = 0;
      int totalSize = list.size();
      while (true) {
        // 以100条记录为单位分批存储
        int end = Math.min(start + 100, totalSize);
        metadataTableColumnPartitionHistoryService.batchInsert(list.subList(start, end));
        if (end >= totalSize) {
          break;
        }
        start = end;
      }
    }
  }

  public Boolean batchDelete(List<String> ids) {
    if (CollectionUtils.isEmpty(ids)) {
      throw new BusinessException("传入的参数主键为空");
    }
    try {
      for (String tableId : ids) {
        BdpTableDTO tableDTO = selectByPrimaryKey(tableId);
        CheckParaUtils.checkDbObjectValidity(
            tableDTO, logger, String.format("没有查到数据，请确保id:%s的数据是否存在", tableId));

        if (tableDTO.getType() != null
            && tableDTO.getType() == TableTypeEnum.TABLE_METADATA.getCode()) {
          // 审批中的数据，需要先撤回申请
          if (tableDTO.getStatus() == DataStateEnum.UNDER_APPROVAL.getCode()) {
            throw new BusinessException("该元数据正在审批中，请先撤回!");
          }
          // todo 已经被引用的元数据，不允许直接删除，给出提示:该元数据已经被引用，不能删除

          // 历史版本如果有已发布的记录，不能删除
          int countStatus =
              metadataTableHistoryService.countByStatus(tableId, DataStateEnum.PUBLISHED.getCode());
          if (countStatus > 0) {
            throw new BusinessException("该元数据有发布的版本存在，暂不能删除!");
          }

          // 删除关联字段的信息
          metadataTableColumnService.deleteColumnByTableId(tableId);
          metadataTableColumnPartitionService.deleteByTableId(tableId);
          metadataTableColumnHistoryService.deleteByTableId(tableId);
          metadataTableColumnPartitionHistoryService.deleteByTableId(tableId);
          metadataTableHistoryService.deleteByTableId(tableId);

          // 删除相关的技术元数据和业务元数据

          deleteByPrimaryKey(tableId);
          BdpLogUtil.log4Delete(tableDTO);
        }
      }
      return true;
    } catch (Exception e) {
      throw new BusinessException(e.getMessage(), e);
    }
  }

  public MetadataTableVo queryById(String id) {
    BdpTableDTO tableDTO = this.mapper.selectById(id);
    Objects.requireNonNull(tableDTO, "元数据不存在");
    handleTableInfo(tableDTO);
    MetadataTableVo vo = getMetadataTableVo(tableDTO);
    String logTitle = "查看元数据：【" + JSONObject.toJSONString(vo) + "】";
    BdpLogUtil.log("元数据管理模块", logTitle, PlatformConstant.OpType.select);
    return vo;
  }

  public List<BdpTableDTO> queryTableList(
      String dataSourceId, int type, boolean withColumn, List<String> idList) {
    List<BdpTableDTO> bdpTableDTOList = this.mapper.queryTableList(dataSourceId, type, idList);
    if (withColumn) {
      bdpTableDTOList.forEach(this::handleTableInfo);
    }
    return bdpTableDTOList;
  }

  public Boolean publish(List<String> ids) {
    if (CollectionUtils.isNotEmpty(ids)) {
      List<ApprovalDTO> approvalList = new ArrayList<>(ids.size());
      List<BdpTableDTO> updateList = new ArrayList<>(ids.size());
      List<BdpTableHistoryDTO> updateHistoryList = new ArrayList<>(ids.size());

      for (String id : ids) {
        BdpTableDTO bdpTableDTO = this.selectByPrimaryKey(id);

        if (bdpTableDTO.getStatus() == DataStateEnum.PUBLISHED.getCode()
            || bdpTableDTO.getStatus() == DataStateEnum.UNDER_APPROVAL.getCode()
            || bdpTableDTO.getStatus() == DataStateEnum.DEPRECATED.getCode()) {
          throw new BusinessException(
              "元数据【" + bdpTableDTO.getName() + "】在状态为审批中或已发布或已废止，不能执行发布操作!");
        }

        bdpTableDTO.setStatus(DataStateEnum.UNDER_APPROVAL.getCode());
        updateList.add(bdpTableDTO);

        BdpTableHistoryDTO bdpTableHistoryDTO = new BdpTableHistoryDTO();
        bdpTableHistoryDTO.setTableId(id);
        bdpTableHistoryDTO.setStatus(DataStateEnum.UNDER_APPROVAL.getCode());
        bdpTableHistoryDTO.setTableVersion(bdpTableDTO.getTableVersion());
        updateHistoryList.add(bdpTableHistoryDTO);

        ApprovalDTO approvalDTO = new ApprovalDTO();
        approvalDTO.setBusinessId(id);
        approvalDTO.setBusinessName(bdpTableDTO.getName());
        approvalDTO.setBusinessVersion(bdpTableDTO.getTableVersion());
        approvalList.add(approvalDTO);
      }

      // 向审批中心发送发布请求
      Boolean releaseResult = metadataApprovalRpc.release(approvalList);
      if (releaseResult && CollectionUtils.isNotEmpty(updateList)) {
        if (this.mapper.batchUpdate(updateList) > 0) {
          return metadataTableHistoryService.batchUpdate(updateHistoryList);
        }
      }

      return false;
    }

    return false;
  }

  /** 接收审批中心通知 */
  public boolean receiveMsgFromApprovalCenter(List<ApprovalDTO> approvalList) {
    if (CollectionUtils.isEmpty(approvalList)) {
      return true;
    }

    List<BdpTableDTO> updateList = new ArrayList<>(approvalList.size());
    List<BdpTableHistoryDTO> updateHistoryList = new ArrayList<>(approvalList.size());

    for (ApprovalDTO approval : approvalList) {
      if (approval == null) {
        continue;
      }
      if (StringUtils.isAnyEmpty(approval.getBusinessId(), approval.getBusinessVersion())) {
        continue;
      }
      if (approval.getApprovalResultType() == null) {
        continue;
      }

      BdpTableDTO bdpTableDTO = this.selectByPrimaryKey(approval.getBusinessId());
      if (bdpTableDTO == null) {
        continue;
      }

      if (approval.getApprovalResultType().equals(0)) {
        // 审批通过，设置为“已发布”状态
        bdpTableDTO.setStatus(DataStateEnum.PUBLISHED.getCode());
      } else if (approval.getApprovalResultType().equals(1)) {
        // 审批不通过通过，设置为“已驳回”状态
        bdpTableDTO.setStatus(DataStateEnum.REJECTED.getCode());
      } else {
        continue;
      }

      bdpTableDTO.setTableVersion(approval.getBusinessVersion());
      updateList.add(bdpTableDTO);

      BdpTableHistoryDTO bdpTableHistoryDTO = new BdpTableHistoryDTO();
      bdpTableHistoryDTO.setId(approval.getBusinessId());
      bdpTableHistoryDTO.setTableVersion(bdpTableDTO.getTableVersion());
      bdpTableHistoryDTO.setStatus(bdpTableDTO.getStatus());
      updateHistoryList.add(bdpTableHistoryDTO);
    }

    if (CollectionUtils.isNotEmpty(updateList)) {
      int updateNum = this.mapper.batchUpdate(updateList);
      if (updateNum > 0) {
        return metadataTableHistoryService.batchUpdate(updateHistoryList);
      }
    }

    return false;
  }

  public boolean offline(List<String> ids) {
    if (CollectionUtils.isNotEmpty(ids)) {
      List<BdpTableDTO> updateList = new ArrayList<>(ids.size());
      List<BdpTableHistoryDTO> updateHistoryList = new ArrayList<>(ids.size());

      for (String id : ids) {
        BdpTableDTO bdpTableDTO = this.selectByPrimaryKey(id);

        if (bdpTableDTO == null) {
          throw new BusinessException("根据ID【+" + id + "】未找到数据");
        }

        if (bdpTableDTO.getStatus() != null
            && bdpTableDTO.getStatus() != DataStateEnum.PUBLISHED.getCode()) {
          throw new BusinessException("该元数据不在已发布状态，不能执行废止操作!");
        }

        // todo 存在引用关系的，不能下线

        bdpTableDTO.setStatus(DataStateEnum.DEPRECATED.getCode());
        updateList.add(bdpTableDTO);

        BdpTableHistoryDTO bdpTableHistoryDTO = new BdpTableHistoryDTO();
        bdpTableHistoryDTO.setId(id);
        bdpTableHistoryDTO.setTableVersion(bdpTableDTO.getTableVersion());
        bdpTableHistoryDTO.setStatus(DataStateEnum.DEPRECATED.getCode());
        updateHistoryList.add(bdpTableHistoryDTO);
      }

      if (CollectionUtils.isNotEmpty(updateList)) {
        int updateNum = this.mapper.batchUpdate(updateList);
        if (updateNum > 0) {
          return metadataTableHistoryService.batchUpdate(updateHistoryList);
        }
      }

      return false;
    }
    return false;
  }

  public Boolean revoke(List<String> ids) {
    if (CollectionUtils.isNotEmpty(ids)) {
      List<ApprovalDTO> approvalList = new ArrayList<>(ids.size());

      List<BdpTableDTO> updateList = new ArrayList<>(ids.size());
      List<BdpTableHistoryDTO> updateHistoryList = new ArrayList<>(ids.size());

      for (String id : ids) {
        BdpTableDTO bdpTableDTO = this.selectByPrimaryKey(id);
        CheckParaUtils.checkDbObjectValidity(
            bdpTableDTO, logger, String.format("没有查到数据，请确保id:%s的数据是否存在", id));

        if (bdpTableDTO.getStatus() != null
            && bdpTableDTO.getStatus() != DataStateEnum.UNDER_APPROVAL.getCode()) {
          throw new BusinessException("该数据不在审批状态，无能撤回!");
        }

        bdpTableDTO.setStatus(DataStateEnum.UNDER_EDITING.getCode());
        updateList.add(bdpTableDTO);

        BdpTableHistoryDTO bdpTableHistoryDTO = new BdpTableHistoryDTO();
        bdpTableHistoryDTO.setId(id);
        bdpTableHistoryDTO.setTableVersion(bdpTableDTO.getTableVersion());
        bdpTableHistoryDTO.setStatus(DataStateEnum.UNDER_EDITING.getCode());
        updateHistoryList.add(bdpTableHistoryDTO);

        ApprovalDTO approvalDTO = new ApprovalDTO();
        approvalDTO.setBusinessId(id);
        approvalDTO.setBusinessName(bdpTableDTO.getName());
        approvalDTO.setBusinessVersion(bdpTableDTO.getTableVersion());
        approvalList.add(approvalDTO);
      }

      // 向审批中心发送撤回请求
      Boolean releaseResult = metadataApprovalRpc.revoke(approvalList);
      if (releaseResult && CollectionUtils.isNotEmpty(updateList)) {
        int updateNum = this.mapper.batchUpdate(updateList);
        if (updateNum > 0) {
          return metadataTableHistoryService.batchUpdate(updateHistoryList);
        }
      }

      return false;
    }
    return false;
  }

  public void batchUpdateCatalogId(String catalogId, List<String> dataAssetIdList) {
    this.mapper.batchUpdateCatalogId(catalogId, dataAssetIdList);
  }

  public List<MetadataModelAttributeDTO> getBusinessList(String id) {
    BdpTableDTO tableDTO = selectByPrimaryKey(id);
    Objects.requireNonNull(tableDTO, "元数据不存在");

    DataSourceDTO dataSourceDTO = dataSourceService.queryDataSourceById(tableDTO.getDataSourceId());
    Objects.requireNonNull(dataSourceDTO, "数据源不存在");
    String dataSourceType = dataSourceDTO.getDatasourceType();
    if (DataSourceType.isRDBMS(dataSourceType)) {
      dataSourceType = "rdbms";
    }

    MetadataModelDTO metadataModelDTO = metadataModelService.queryByType(dataSourceType);
    Objects.requireNonNull(metadataModelDTO, "元模型不存在");

    MetadataModelAttributeDTO query = new MetadataModelAttributeDTO();
    query.setMetadataModelId(metadataModelDTO.getId());
    query.setType(MetadataModelAttributeDTO.TYPE_BUS);
    query.setValidFlag(Constants.STATUS_ONE);

    List<MetadataModelAttributeDTO> list = metadataModelAttributeService.selectList(query);
    if (CollectionUtils.isNotEmpty(list)) {
      for (MetadataModelAttributeDTO dto : list) {
        if (StringUtils.isNotEmpty(dto.getOptionAttribute())) {
          dto.setOptionAttributeList(
              JSONUtils.toList(dto.getOptionAttribute(), OptionAttribute.class));
        }

        if (StringUtils.isNotEmpty(dto.getLookupTableId())) {
          LookupTableDto lookupTableDto =
              lookupTableService.selectByPrimaryKey(dto.getLookupTableId());
          if (lookupTableDto != null) {
            dto.setLookupTableName(lookupTableDto.getName());
            List<LookupTableValueDto> lookupTableValueList =
                lookupTableValueService.selectByLookupTableId(dto.getLookupTableId());
            List<OptionAttribute> optionAttributes =
                lookupTableValueList.stream()
                    .map(t -> new OptionAttribute(t.getValue(), t.getName()))
                    .collect(Collectors.toList());
            dto.setOptionAttributeList(optionAttributes);
          }
        }
      }

      List<MetadataBusinessDto> businessList =
          metadataBusinessDao.getBusinessList(tableDTO.getId(), tableDTO.getTableVersion());
      if (CollectionUtils.isNotEmpty(businessList)) {
        Map<String, String> map =
            businessList.stream()
                .filter(t -> StringUtils.isNotEmpty(t.getValue()))
                .collect(
                    Collectors.toMap(
                        MetadataBusinessDto::getBusinessId, MetadataBusinessDto::getValue));

        for (MetadataModelAttributeDTO dto : list) {
          if (map.containsKey(dto.getId())) {

            dto.setValue(map.get(dto.getId()));

            if ("domain".equalsIgnoreCase(dto.getAttributeCode())) {
              dto.setDisplayValue(this.mapper.getMetadataDomain(map.get(dto.getId())));
            } else if ("dataHierarchy".equalsIgnoreCase(dto.getAttributeCode())) {
              dto.setDisplayValue(this.mapper.getMetadataDataHierarchy(map.get(dto.getId())));
            } else if ("owner".equalsIgnoreCase(dto.getAttributeCode())) {
              if (StringUtils.isNotBlank(dto.getValue())) {
                try {
                  JSONArray array = JSONUtils.parseArray(dto.getValue());
                  List<String> idList = array.toJavaList(String.class);
                  List<SysUser> userList = sysUserClient.getUserListByIdList(idList);
                  if (CollectionUtils.isNotEmpty(userList)) {
                    List<String> userNameList =
                        userList.stream().map(SysUser::getName).collect(Collectors.toList());
                    dto.setDisplayValue(String.join(",", userNameList));
                  }
                } catch (Exception e) {
                  logger.error("解析owner失败", e);
                }
              }
            } else {
              dto.setDisplayValue(map.get(dto.getId()));
            }
          }
        }
      }
    }
    return list;
  }

  public Boolean batchUpdateBusinessList(MetadataBusinessUpdateDto updateDto) {

    String metaDataId = updateDto.getTableId();
    CheckParaUtils.checkStringValidity(metaDataId, logger, "表ID不能为空");

    BdpTableDTO bdpTableDTO = this.mapper.selectByPrimaryKey(metaDataId);
    CheckParaUtils.checkObjectValidity(bdpTableDTO, logger, "元数据不存在");

    List<MetadataBusinessDto> list = updateDto.getBusinessModify();
    if (CollectionUtils.isNotEmpty(list)) {
      List<MetadataBusinessDto> addList = new ArrayList<>();

      for (MetadataBusinessDto dto : list) {

        CheckParaUtils.checkStringValidity(dto.getBusinessId(), logger, "ID不能为空");

        dto.setMetadataVersion(bdpTableDTO.getTableVersion());

        if (dto.getValue() != null) {
          dto.setId(ComUtil.getId());
          dto.setTableId(updateDto.getTableId());
          EntityUtils.setCreateAndUpdateInfo(dto);
          addList.add(dto);
        }
      }

      MetadataBusinessDto deleteQuery = new MetadataBusinessDto();
      deleteQuery.setTableId(updateDto.getTableId());
      deleteQuery.setMetadataVersion(bdpTableDTO.getTableVersion());
      metadataBusinessDao.delete(deleteQuery);

      if (CollectionUtils.isNotEmpty(addList)) {
        metadataBusinessDao.batchInsertBusinessList(addList);
      }

      String logTitle = "修改元数据：【" + JSONObject.toJSONString(addList) + "】";
      BdpLogUtil.log("元数据管理模块", logTitle, PlatformConstant.OpType.update);
      return true;
    }

    return false;
  }

  public List<MetadataModelAttributeDTO> getTechnologyList(String id) {
    BdpTableDTO tableDTO = selectByPrimaryKey(id);
    Objects.requireNonNull(tableDTO, "元数据不存在");
    DataSourceDTO dataSourceDTO = dataSourceService.queryDataSourceById(tableDTO.getDataSourceId());
    Objects.requireNonNull(dataSourceDTO, "数据源不存在");
    String dataSourceType = dataSourceDTO.getDatasourceType();
    if (DataSourceType.isRDBMS(dataSourceType)) {
      dataSourceType = "rdbms";
    }
    MetadataModelDTO metadataModelDTO = metadataModelService.queryByType(dataSourceType);
    Objects.requireNonNull(metadataModelDTO, "元模型不存在");

    MetadataModelAttributeDTO query = new MetadataModelAttributeDTO();
    query.setMetadataModelId(metadataModelDTO.getId());
    query.setType(MetadataModelAttributeDTO.TYPE_TECH);
    query.setValidFlag(Constants.STATUS_ONE);

    List<MetadataModelAttributeDTO> list = metadataModelAttributeService.selectList(query);
    if (CollectionUtils.isNotEmpty(list)) {
      MetadataStateDto metadataStateDto =
          metadataStateService.getLatestByDatasourceAndTable(
              tableDTO.getDataSourceId(), tableDTO.getName());
      if (metadataStateDto != null) {
        for (MetadataModelAttributeDTO dto : list) {
          if (dto.getAttributeCode().equalsIgnoreCase("statDate")) {
            dto.setValue(metadataStateDto.getStatDate().toString());
          } else if (dto.getAttributeCode().equalsIgnoreCase("dataSourceId")) {
            dto.setValue(metadataStateDto.getDataSourceId());
          } else if (dto.getAttributeCode().equalsIgnoreCase("tableId")) {
            dto.setValue(metadataStateDto.getTableId());
          } else if (dto.getAttributeCode().equalsIgnoreCase("tableVersion")) {
            dto.setValue(metadataStateDto.getTableVersion());
          } else if (dto.getAttributeCode().equalsIgnoreCase("tableName")) {
            dto.setValue(metadataStateDto.getTableName());
          } else if (dto.getAttributeCode().equalsIgnoreCase("dataType")) {
            dto.setValue(metadataStateDto.getDataType());
          } else if (dto.getAttributeCode().equalsIgnoreCase("databaseName")) {
            dto.setValue(metadataStateDto.getDatabaseName());
          } else if (dto.getAttributeCode().equalsIgnoreCase("memorySpace")) {
            if (metadataStateDto.getMemorySpace() != null) {
              String unit = FileUtils.formatNumber(metadataStateDto.getMemorySpace());
              dto.setValue(
                  FileUtils.formatAmountUnit(unit, metadataStateDto.getMemorySpace()) + unit);
            }
          } else if (dto.getAttributeCode().equalsIgnoreCase("recordCount")) {
            dto.setValue(metadataStateDto.getRecordCount().toString());
          } else if (dto.getAttributeCode().equalsIgnoreCase("tableCreateTime")) {
            dto.setValue(metadataStateDto.getTableCreateTime());
          } else if (dto.getAttributeCode().equalsIgnoreCase("ddlLastUpdateTime")) {
            dto.setValue(metadataStateDto.getDdlLastUpdateTime());
          } else if (dto.getAttributeCode().equalsIgnoreCase("dataLastUpdateTime")) {
            dto.setValue(metadataStateDto.getDataLastUpdateTime());
          } else if (dto.getAttributeCode().equalsIgnoreCase("latestSyncTime")) {
            dto.setValue(metadataStateDto.getLatestSyncTime());
          } else if (dto.getAttributeCode().equalsIgnoreCase("tableType")) {
            dto.setValue(metadataStateDto.getTbType());
          }
        }
      }
    }
    return list;
  }

  public Map<String, Object> preview(String id, Integer currentPage, Integer pageSize) {
    BdpTableDTO metadataTable = this.selectByPrimaryKey(id);
    Objects.requireNonNull(metadataTable, "metadataTable is null");
    DataSourceDTO datasource =
        dataSourceService.selectByPrimaryKey(metadataTable.getDataSourceId());
    Objects.requireNonNull(datasource, "datasource is null");
    String sql =
        "select * from "
            + DBUtils.convertTableName(datasource.getDatasourceType(), metadataTable.getName());

    return dataQueryService.getDataListByTable(
        metadataTable, null, sql, null, currentPage, pageSize);
  }

  public Page<CommonResVo> getColumnPageList(
      String tableId, String keyWords, Integer pageNo, Integer pageSize) {
    Page<BdpColumnDTO> pageList =
        metadataTableColumnService.selectPageList(tableId, keyWords, pageNo, pageSize);
    List<CommonResVo> voList = new ArrayList<>();
    List<BdpColumnDTO> columnDTOS = pageList.getResult();

    for (BdpColumnDTO columnDTO : columnDTOS) {
      CommonResVo commonResVo = new CommonResVo(columnDTO.getId(), columnDTO.getName());
      voList.add(commonResVo);
    }

    Page<CommonResVo> page = new Page<>(pageNo, pageSize);
    page.setTotal(pageList.getTotal());
    page.addAll(voList);
    return page;
  }

  public MetadataTableVo queryByDataSourceIdAndName(
      String metadataCollectTaskId, String datasourceId, String name) {
    BdpTableDTO query = new BdpTableDTO();
    query.setName(name);
    query.setMetadataCollectTaskId(metadataCollectTaskId);
    query.setDataSourceId(datasourceId);
    query.setType(TableTypeEnum.TABLE_METADATA.getCode());
    BdpTableDTO bdpTableDTO = this.selectOne(query);
    if (bdpTableDTO == null) {
      throw new DaoException("数据不存在");
    }
    return getMetadataTableVo(bdpTableDTO);
  }

  public int deleteByDatasourceId(String datasourceId) {
    return this.mapper.deleteByDatasourceId(datasourceId);
  }
}
